package cn.com.doone.common.uc.service.impl;

import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.com.doone.common.uc.domain.oauth.AccessToken;
import cn.com.doone.common.uc.domain.oauth.AuthenticationIdGenerator;
import cn.com.doone.common.uc.domain.oauth.ClientDetails;
import cn.com.doone.common.uc.domain.oauth.OauthCode;
import cn.com.doone.common.uc.domain.oauth.OauthRepository;
import cn.com.doone.common.uc.infrastructure.DateUtils;
import cn.com.doone.common.uc.infrastructure.ldap.OauthLdapRepository;
import cn.com.doone.common.uc.service.OauthService;
import cn.com.doone.common.uc.service.dto.IpBlackList;
import cn.com.doone.common.uc.service.dto.LoginLog;
import cn.com.doone.common.uc.utils.DES3;
import cn.com.doone.common.uc.utils.PasswordUtils;
import cn.com.doone.common.uc.utils.PropertiesUtils;
import cn.com.doone.common.uc.utils.StringUtils;
import cn.com.doone.common.uc.web.WebUtils;

/**
 * 15-6-10
 *
 * @author Shengzhao Li
 */
@Service("oauthService")
public class OauthServiceImpl implements OauthService {

    private static final Logger LOG = LoggerFactory.getLogger(OauthServiceImpl.class);

    @Autowired
    private OauthLdapRepository oauthLdapRepository;
    
    @Autowired
    private PropertiesUtils propertiesUtils;

    @Autowired
    private OauthRepository oauthRepository;
    @Autowired
    private AuthenticationIdGenerator authenticationIdGenerator;
    @Autowired
    private OAuthIssuer oAuthIssuer;

    @Override
    public ClientDetails loadClientDetails(String clientId) {
        LOG.debug("Load ClientDetails by clientId: {}", clientId);
        return oauthRepository.findClientDetails(clientId);
    }

    @Override
    public OauthCode saveAuthorizationCode(String authCode, ClientDetails clientDetails) {
        final String username = currentUsername();
        OauthCode oauthCode = new OauthCode()
                .code(authCode).username(username)
                .clientId(clientDetails.getClientId());

        oauthRepository.saveOauthCode(oauthCode);
        LOG.debug("Save OauthCode: {}", oauthCode);
        return oauthCode;
    }

    private String currentUsername() {
        return (String) SecurityUtils.getSubject().getPrincipal();
    }

    @Override
    public String retrieveAuthCode(ClientDetails clientDetails) throws OAuthSystemException {
        final String clientId = clientDetails.getClientId();
        final String username = currentUsername();

        OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(username, clientId);
        if (oauthCode != null) {
            //Always delete exist
            LOG.debug("OauthCode ({}) is existed, remove it and create a new one", oauthCode);
            oauthRepository.deleteOauthCode(oauthCode);
        }
        //create a new one
        oauthCode = createOauthCode(clientDetails);

        return oauthCode.code();
    }
    
    @Override
	public void removeAuthCode(String clientId, String username) {
    	OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(username, clientId);
    	if (oauthCode != null) {
            oauthRepository.deleteOauthCode(oauthCode);
        }
	}
    
    @Override
	public String retrieveAuthCode(Map<String, Object> params) throws OAuthSystemException {
		String clientId = params.get("client_id").toString();
		String userName = params.get("username").toString();
		OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(userName, clientId);
		if (oauthCode != null) {
            //Always delete exist
            LOG.debug("OauthCode ({}) is existed, remove it and create a new one", oauthCode);
            oauthRepository.deleteOauthCode(oauthCode);
        }
		
    	final String authCode = oAuthIssuer.authorizationCode();
    	oauthCode = new OauthCode().code(authCode).clientId(clientId).username(userName);
		
		oauthRepository.saveOauthCode(oauthCode);
        LOG.debug("Save OauthCode: {}", oauthCode);

        return oauthCode.code();
	}

    @Override
    public AccessToken retrieveAccessToken(ClientDetails clientDetails, Set<String> scopes) throws OAuthSystemException {
        return retrieveAccessToken(clientDetails, scopes, clientDetails.supportRefreshToken());
    }

    @Override
    public AccessToken retrieveAccessToken(ClientDetails clientDetails, Set<String> scopes, boolean includeRefreshToken) throws OAuthSystemException {
        String scope = OAuthUtils.encodeScopes(scopes);
        final String username = currentUsername();
        final String clientId = clientDetails.getClientId();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);

        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
        if (accessToken == null) {
            accessToken = createAndSaveAccessToken(clientDetails, includeRefreshToken, username, authenticationId);
            LOG.debug("Create a new AccessToken: {}", accessToken);
        }

        return accessToken;
    }

    //Always return new AccessToken, exclude refreshToken
    @Override
    public AccessToken retrieveNewAccessToken(ClientDetails clientDetails, Set<String> scopes) throws OAuthSystemException {
        String scope = OAuthUtils.encodeScopes(scopes);
        final String username = currentUsername();
        final String clientId = clientDetails.getClientId();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);

        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
        if (accessToken != null) {
            LOG.debug("Delete existed AccessToken: {}", accessToken);
            oauthRepository.deleteAccessToken(accessToken);
        }
        accessToken = createAndSaveAccessToken(clientDetails, false, username, authenticationId);
        LOG.debug("Create a new AccessToken: {}", accessToken);

        return accessToken;
    }

    @Override
    public OauthCode loadOauthCode(String code, ClientDetails clientDetails) {
        final String clientId = clientDetails.getClientId();
        return oauthRepository.findOauthCode(code, clientId);
    }

    @Override
    public boolean removeOauthCode(String code, ClientDetails clientDetails) {
        final OauthCode oauthCode = loadOauthCode(code, clientDetails);
        final int rows = oauthRepository.deleteOauthCode(oauthCode);
        return rows > 0;
    }

    /**
     * 根据code取username
     */
    @Override
    public AccessToken retrieveNewAccessToken(ClientDetails clientDetails, String code) throws OAuthSystemException {
    	
    	final String clientId = clientDetails.getClientId();
    	
    	final OauthCode oauthCode = loadOauthCode(code, clientDetails);
    	
        final String username = oauthCode.username();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, null);

        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
        if (accessToken != null) {
            LOG.debug("Delete existed AccessToken: {}", accessToken);
            oauthRepository.deleteAccessToken(accessToken);
        }
        accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
        LOG.debug("Create a new AccessToken: {}", accessToken);

        return accessToken;
    }
    
    //Always return new AccessToken
    @Override
    public AccessToken retrieveNewAccessToken(ClientDetails clientDetails) throws OAuthSystemException {
    	
        final String username = currentUsername();
        final String clientId = clientDetails.getClientId();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, null);

        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
        if (accessToken != null) {
            LOG.debug("Delete existed AccessToken: {}", accessToken);
            oauthRepository.deleteAccessToken(accessToken);
        }
        accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
        LOG.debug("Create a new AccessToken: {}", accessToken);

        return accessToken;
    }
    
    public AccessToken retrieveNewAccessTokenByUsername(ClientDetails clientDetails, String username) throws OAuthSystemException {
    	
        final String clientId = clientDetails.getClientId();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, null);

        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
        if (accessToken != null) {
            LOG.debug("Delete existed AccessToken: {}", accessToken);
            oauthRepository.deleteAccessToken(accessToken);
        }
        accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
        LOG.debug("Create a new AccessToken: {}", accessToken);

        return accessToken;
    }

    //grant_type=password AccessToken
    @Override
    public AccessToken retrievePasswordAccessToken(ClientDetails clientDetails, Set<String> scopes, String username) throws OAuthSystemException {
        String scope = OAuthUtils.encodeScopes(scopes);
        final String clientId = clientDetails.getClientId();

        final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
        AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);

        boolean needCreate = false;
        if (accessToken == null) {
            needCreate = true;
            LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
        } else if (accessToken.tokenExpired()) {
            LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
            oauthRepository.deleteAccessToken(accessToken);
            needCreate = true;
        } else {
            LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
        }

        if (needCreate) {
            accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
            LOG.debug("Create a new AccessToken: {}", accessToken);
        }

        return accessToken;

    }


    //grant_type=client_credentials
    @Override
    public AccessToken retrieveClientCredentialsAccessToken(ClientDetails clientDetails, Set<String> scopes) throws OAuthSystemException {
        String scope = OAuthUtils.encodeScopes(scopes);
        final String clientId = clientDetails.getClientId();
        //username = clientId

        final String authenticationId = authenticationIdGenerator.generate(clientId, clientId, scope);
        AccessToken accessToken = oauthRepository.findAccessToken(clientId, clientId, authenticationId);

        boolean needCreate = false;
        if (accessToken == null) {
            needCreate = true;
            LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
        } else if (accessToken.tokenExpired()) {
            LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
            oauthRepository.deleteAccessToken(accessToken);
            needCreate = true;
        } else {
            LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
        }

        if (needCreate) {
            //Ignore refresh_token
            accessToken = createAndSaveAccessToken(clientDetails, false, clientId, authenticationId);
            LOG.debug("Create a new AccessToken: {}", accessToken);
        }

        return accessToken;

    }

    @Override
    public AccessToken loadAccessTokenByRefreshToken(String refreshToken, String clientId) {
        LOG.debug("Load ClientDetails by refreshToken: {} and clientId: {}", refreshToken, clientId);
        return oauthRepository.findAccessTokenByRefreshToken(refreshToken, clientId);
    }

    /*
    * Get AccessToken
    * Generate a new AccessToken from existed(exclude token,refresh_token)
    * Update access_token,refresh_token, expired.
    * Save and remove old
    * */
    @Override
    public AccessToken changeAccessTokenByRefreshToken(String refreshToken, String clientId) throws OAuthSystemException {
        final AccessToken oldToken = loadAccessTokenByRefreshToken(refreshToken, clientId);

        AccessToken newAccessToken = oldToken.cloneMe();
        LOG.debug("Create new AccessToken: {} from old AccessToken: {}", newAccessToken, oldToken);

        ClientDetails details = oauthRepository.findClientDetails(clientId);
        newAccessToken.updateByClientDetails(details);

        final String authId = authenticationIdGenerator.generate(clientId, oldToken.username(), null);
        newAccessToken.authenticationId(authId)
                .tokenId(oAuthIssuer.accessToken())
                .refreshToken(oAuthIssuer.refreshToken());

        oauthRepository.deleteAccessToken(oldToken);
        LOG.debug("Delete old AccessToken: {}", oldToken);

        oauthRepository.saveAccessToken(newAccessToken);
        LOG.debug("Save new AccessToken: {}", newAccessToken);

        return newAccessToken;
    }
    
    @Override
    public AccessToken loadAccessToken(String clientId, String username, Set<String> scopes) {
    	String scope = scopes == null ? null :OAuthUtils.encodeScopes(scopes);
        final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
    	LOG.debug("Load AccessToken by authenticationId: {}", authenticationId);
    	
    	return this.oauthRepository.findAccessToken(clientId, username, authenticationId);
    }
    
    @Override
    public Map<String, Object> findAppInfo(String appCode) {
    	LOG.debug("find AppInfo by appCode: {}", appCode);
    	return this.oauthRepository.findAppInfo(appCode);
    }
    
    @Override
    public Map<String, Object> findUserInfoByUserAccount(String userAccount) {
    	LOG.debug("find UserInfoByUserAccount by userAccount: {}", userAccount);
    	return this.oauthRepository.findUserInfoByUserAccount(userAccount);
    }
    
    @Override
    public Map<String, Object> findUserGroupAppAuthorize(int userGroupId, int appInfoId) {
    	LOG.debug("find UserGroupAppAuthorize by userGroupId: {} and appInfoId: {}", userGroupId, appInfoId);
    	return this.oauthRepository.findUserGroupAppAuthorize(userGroupId, appInfoId);
    }
    
    @Override
    public boolean valiUserAndAppAuthorize(int userId, int appInfoId) {
    	LOG.debug("vali UserAndAppAuthorize by userId: {} and appInfoId: {}", userId, appInfoId);
    	return this.oauthRepository.valiUserAndAppAuthorize(userId, appInfoId);
    }
    
    @Override
    public boolean valiUserGroupAndAppAuthorize(int userId, int appInfoId) {
    	LOG.debug("vali UserGroupAndAppAuthorize by userId: {} and appInfoId: {}", userId, appInfoId);
    	List<Integer> userGroupIdList = this.oauthRepository.findUserGroupByUserId(userId);
    	
    	int count = 0;
    	
    	for (Integer userGroupId : userGroupIdList) {
    		count += this.oauthRepository.countUserGroupAndAppAuthorize(userGroupId, appInfoId);
    	}
    	
    	return count == 0 ? false : true;
    }
    
    @Override
    public boolean valiIPBlackList(String ip) {
    	LOG.debug("vali IPBlackList by ip: {}", ip);
    	return this.oauthRepository.valiIPBlackList(ip);
    }

    private AccessToken createAndSaveAccessToken(ClientDetails clientDetails, boolean includeRefreshToken, String username, String authenticationId) throws OAuthSystemException {
        AccessToken accessToken = new AccessToken()
                .clientId(clientDetails.getClientId())
                .username(username)
                .tokenId(oAuthIssuer.accessToken())
                .authenticationId(authenticationId)
                .updateByClientDetails(clientDetails);

        if (includeRefreshToken) {
            accessToken.refreshToken(oAuthIssuer.refreshToken());
        }

        this.oauthRepository.saveAccessToken(accessToken);
        LOG.debug("Save AccessToken: {}", accessToken);
        return accessToken;
    }

    private OauthCode createOauthCode(ClientDetails clientDetails) throws OAuthSystemException {
        OauthCode oauthCode;
        final String authCode = oAuthIssuer.authorizationCode();

        LOG.debug("Save authorizationCode '{}' of ClientDetails '{}'", authCode, clientDetails);
        oauthCode = this.saveAuthorizationCode(authCode, clientDetails);
        return oauthCode;
    }
    
    @Override
    public void saveIPBlackListInfo(IpBlackList ipBlackList) {
    	this.oauthRepository.saveIPBlackListInfo(ipBlackList);
    	
    }
    
    @Override
    public void deleteIPBlackListInfo(String ip) {
    	this.oauthRepository.deleteIPBlackListInfo(ip);
    	
    }
    
    @Override
    public void updateIPBlackListInfoByIP(String ip, String invalidTime, String remarks) {
    	this.oauthRepository.updateIPBlackListInfoByIP(ip, invalidTime, remarks);
    	
    }
    
    @Override
    public void updateIPBlackListInfoByID(int id, String ip, String invalidTime, String remarks) {
    	this.oauthRepository.updateIPBlackListInfoByID(id, ip, invalidTime, remarks);
    	
    }
    
    @Override
    public boolean valiIPExitBlackList(String ip) {
    	
    	return this.oauthRepository.valiIPExitBlackList(ip);
    }
    
    @Override
    public boolean valiIPWhiteList(String ip) {
    	
    	return this.oauthRepository.valiIPWhiteList(ip);
    }
    
    @Override
    public List<Map<String, Object>> findIPBlackList(String ip, String createTimeStart, String createTimeEnd, String invalidTimeStart, String invalidTimeEnd) {
    	StringBuffer searchWhere = new StringBuffer(" where 1=1");
    	if(ip != null && !ip.isEmpty()){
    		searchWhere.append(" and ibl.IP like '%" + ip + "%'");
    	}
    	if(createTimeStart != null && !createTimeStart.isEmpty()){
    		searchWhere.append(" and ibl.CREATE_TIME >= '" + createTimeStart + "'");
    	}
    	if(createTimeEnd != null && !createTimeEnd.isEmpty()){
    		searchWhere.append(" and ibl.CREATE_TIME <= '" + createTimeEnd + "'");
    	}
    	if(invalidTimeStart != null && !invalidTimeStart.isEmpty()){
    		searchWhere.append(" and ibl.INVALID_TIME >= '" + invalidTimeStart + "'");
    	}
    	if(invalidTimeEnd != null && !invalidTimeEnd.isEmpty()){
    		searchWhere.append(" and ibl.INVALID_TIME <= '" + invalidTimeEnd + "'");
    	}
    	
    	return this.oauthRepository.findIPBlackList(searchWhere.toString());
    }
    
    @Override
    public List<Map<String, Object>> findIPWhiteList(String ip, String createTimeStart, String createTimeEnd, String invalidTimeStart, String invalidTimeEnd) {
    	StringBuffer searchWhere = new StringBuffer(" where 1=1");
    	if(ip != null && !ip.isEmpty()){
    		searchWhere.append(" and iwl.IP like '%" + ip + "%'");
    	}
    	if(createTimeStart != null && !createTimeStart.isEmpty()){
    		searchWhere.append(" and iwl.CREATE_TIME >= '" + createTimeStart + "'");
    	}
    	if(createTimeEnd != null && !createTimeEnd.isEmpty()){
    		searchWhere.append(" and iwl.CREATE_TIME <= '" + createTimeEnd + "'");
    	}
    	if(invalidTimeStart != null && !invalidTimeStart.isEmpty()){
    		searchWhere.append(" and iwl.INVALID_TIME >= '" + invalidTimeStart + "'");
    	}
    	if(invalidTimeEnd != null && !invalidTimeEnd.isEmpty()){
    		searchWhere.append(" and iwl.INVALID_TIME <= '" + invalidTimeEnd + "'");
    	}
    	
    	return this.oauthRepository.findIPWhiteList(searchWhere.toString());
    }
    
    @Override
    public void saveUserAppAuthorize(int userId, int appInfoId) {
    	LOG.debug("Save userAppAuthorize userId : {} and appInfoId : {}", userId, appInfoId);
    	// 删除旧授权
    	this.oauthRepository.deleteUserAppAuthorize(userId, appInfoId);
    	// 添加新授权
    	this.oauthRepository.saveUserAppAuthorize(userId, appInfoId);
    }
    
    @Override
    public boolean validWeakPassword(String password) {
    	LOG.debug("valid weak password : ", password);
    	return this.oauthRepository.validWeakPassword(password);
    }

	@Override
	public boolean validCorrectPassword(String userAccount, String password, HttpServletRequest request) throws NoSuchAlgorithmException {
		LOG.debug("valid is password correct: ", password);
		
		Map<String, Object> userInfoMap = this.oauthRepository.findUserInfoByUserAccount(userAccount);
		
		if (userInfoMap == null) {
			return false;
		}
		
		// mysql认证
		String tempStaffId = (String) userInfoMap.get("TEMP_STAFF_ID");
		String encryptionType = (String) userInfoMap.get("ENCRYPTION_TYPE");
		
		if (tempStaffId == null) {
			tempStaffId = "";
		}
		
		if (encryptionType.equals("1")) {
			password = PasswordUtils.md5Password(tempStaffId + password);
		} else if (encryptionType.equals("2")) {
			password = PasswordUtils.openLdapMD5(password);
		}
		
		
		boolean isCorrect = this.oauthRepository.isCorrectPassword(userAccount, password);
		
		int userInfoId = 0;
		if (userInfoMap != null) {
			userInfoId = (Integer) userInfoMap.get("USER_INFO_ID");
		}
    	
		
		LoginLog loginLog = new LoginLog();
		String ipAdrress = WebUtils.retrieveClientIp(request);
		String macAddress = "";
		 
		loginLog.setUserInfoId(userInfoId);
		loginLog.setUserAccount(userAccount);
		loginLog.setIsSuccess(isCorrect ? "1" : "0"); // 正确"1"，错误"0"
		loginLog.setIpAddress(ipAdrress);
		loginLog.setMacAddress(macAddress);
		
		this.oauthRepository.saveLoginLog(loginLog);
		return isCorrect;
	}

	@Override
	public void changePassword(String userAccount, String password,String p_code) {
		LOG.debug("change password userAccount : {} and password : {}", userAccount, password);
		this.oauthRepository.changePassword(userAccount, password,p_code);
		
		if (propertiesUtils.isLdapEnable()) {
			// 修改ldap密码
			this.oauthLdapRepository.changePassword(userAccount, password);
		}
	}

	@Override
	public void saveLoginLog(LoginLog loginLog) {
		LOG.debug("save loginlog");
		this.oauthRepository.saveLoginLog(loginLog);
	}

	@Override
	public int findUserInfoIdByAccount(String userAccount) {
		LOG.debug("find userInfoId by userAccount");
		return this.oauthRepository.findUserInfoIdByAccount(userAccount);
	}

	@Override
	public int countLoginLogByIp(String ip, String startTime, String endTime) {
		LOG.debug("count loginLog by ip");
		return this.oauthRepository.countLoginLogByIp(ip, startTime, endTime);
	}

	@Override
	public int countLoginLogByUserId(int userInfoId, String startTime, String endTime) {
		LOG.debug("count loginLog by userInfoId");
		return this.oauthRepository.countLoginLogByUserId(userInfoId, startTime, endTime);
	}

	@Override
	public void updateUserLock(Map<String, Object> userMap) {
		LOG.debug("update userinfo lock");
		this.oauthRepository.updateUserLock(userMap);
	}

	@Override
	public void validAccountLock(Map<String, Object> resultMap) {
		
		boolean isLock = true;
    	String userAccount = (String) resultMap.get("userAccount");
    	
    	Date currentTime = new Date();
    	
    	Map<String, Object> userInfoMap = this.oauthRepository.findUserInfoByUserAccount(userAccount);
    	

		if (userInfoMap == null) {
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "账号名或密码错误！");
    		isLock = false;
		}
		
		int userInfoId = 0;
		String lockLevel = "";
		Date invalidTime = null;
		
		if (isLock) {
			userInfoId = (Integer) userInfoMap.get("USER_INFO_ID");
	    	lockLevel = (String) userInfoMap.get("LOCK_LEVEL");
	    	invalidTime = (Date) userInfoMap.get("INVALID_TIME");
		}
    	
    	if (isLock && "4".equals(lockLevel)) {
    		resultMap.put("error", true);
    		resultMap.put("errorMessage", "您的账号已被永久锁定，请联系系统管理员。");
    		isLock = false;
		}
    	
		if (isLock && invalidTime != null && currentTime.before(invalidTime)) {
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "您的账号将于" + DateUtils.toDateTime(invalidTime) + "后解锁，请稍后再试。");
    		isLock = false;
		}
		
		Date startTimeM5 = DateUtils.dayAddAndSub(Calendar.MINUTE , -5);
		int failCountM5 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeM5), DateUtils.toDateTime(currentTime));
		Date startTimeM60 = DateUtils.dayAddAndSub(Calendar.HOUR , -1);
		int failCountM60 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeM60), DateUtils.toDateTime(currentTime));
		Date startTimeH24 = DateUtils.dayAddAndSub(Calendar.DATE , -1);
		int failCountH24 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeH24), DateUtils.toDateTime(currentTime));
		Date startTimeH120 = DateUtils.dayAddAndSub(Calendar.DATE , -5);
		int failCountH120 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeH120), DateUtils.toDateTime(currentTime));
		
		if (isLock && failCountH120 >= 25) {
			
			Map<String,Object> userMap = new HashMap<String,Object>();
			
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "4");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.YEAR , 100));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败次数过多，现已被永久锁定，如需解锁请联系系统管理员。");
    		isLock = false;
		}
		
		if (isLock && failCountH24 >= 15) {
			
			Map<String,Object> userMap = new HashMap<String,Object>();
			
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "3");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.DATE , 3));
			
			this.oauthRepository.updateUserLock(userMap);

			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请72小时之后再尝试。");
    		isLock = false;
		}
		
		if (isLock && failCountM60 >= 10) {
			
			Map<String,Object> userMap = new HashMap<String,Object>();
			
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "2");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.MINUTE , 120));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请120分钟之后再尝试。");
    		isLock = false;
		}
		
		if (isLock && failCountM5 >= 5) {
			
			Map<String,Object> userMap = new HashMap<String,Object>();
			
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "1");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.MINUTE , 5));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请5分钟之后再尝试。");
    		isLock = false;
		}
	}
	
	@Override
	public void validAccountLockByUserId(Map<String,Object> resultMap) {
		String userId = resultMap.get("userInfoId").toString();
		if(StringUtils.isNull(userId)) {
			resultMap.put("error", true);
			resultMap.put("errorMessager", "参数为空");
			return;
		}
		
    	Date currentTime = new Date();
    	
    	Map<String, Object> userInfoMap = this.oauthRepository.findUserInfoByUserId(userId);

		if (userInfoMap == null) {
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "账号名或密码错误！");
    		return;
		}
		
		int userInfoId = (Integer) userInfoMap.get("USER_INFO_ID");
		String lockLevel = userInfoMap.get("LOCK_LEVEL").toString();
		Date invalidTime = (Date) userInfoMap.get("INVALID_TIME");
		
    	if ("4".equals(lockLevel)) {
    		resultMap.put("error", true);
    		resultMap.put("errorMessage", "您的账号已被永久锁定，请联系系统管理员。");
    		return;
		}
    	
		if (invalidTime != null && currentTime.before(invalidTime)) {
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "您的账号将于" + DateUtils.toDateTime(invalidTime) + "后解锁，请稍后再试。");
    		return;
		}
		
		Date startTimeH120 = DateUtils.dayAddAndSub(Calendar.DATE , -5);
		int failCountH120 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeH120), DateUtils.toDateTime(currentTime));
		if (failCountH120 >= 25) {
			Map<String,Object> userMap = new HashMap<String,Object>();
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "4");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.YEAR , 100));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败次数过多，现已被永久锁定，如需解锁请联系系统管理员。");
    		return;
		}
		
		Date startTimeH24 = DateUtils.dayAddAndSub(Calendar.DATE , -1);
		int failCountH24 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeH24), DateUtils.toDateTime(currentTime));
		if (failCountH24 >= 15) {
			Map<String,Object> userMap = new HashMap<String,Object>();
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "3");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.DATE , 3));
			
			this.oauthRepository.updateUserLock(userMap);

			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请72小时之后再尝试。");
    		return;
		}
		
		Date startTimeM60 = DateUtils.dayAddAndSub(Calendar.HOUR , -1);
		int failCountM60 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeM60), DateUtils.toDateTime(currentTime));
		if (failCountM60 >= 10) {
			Map<String,Object> userMap = new HashMap<String,Object>();
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "2");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.MINUTE , 120));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请120分钟之后再尝试。");
    		return;
		}
		
		Date startTimeM5 = DateUtils.dayAddAndSub(Calendar.MINUTE , -5);
		int failCountM5 = this.oauthRepository.countLoginLogByUserId(userInfoId, DateUtils.toDateTime(startTimeM5), DateUtils.toDateTime(currentTime));
		if (failCountM5 >= 5) {
			Map<String,Object> userMap = new HashMap<String,Object>();
			userMap.put("userInfoId", userInfoId);
			userMap.put("lockLevel", "1");
			userMap.put("invalidTime", DateUtils.dayAddAndSub(Calendar.MINUTE , 5));
			
			this.oauthRepository.updateUserLock(userMap);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的账号验证失败的次数过多，现已被锁定，请5分钟之后再尝试。");
    		return;
		}
	}

	@Override
	public void validIpLock(Map<String, Object> resultMap) {
		final HttpServletRequest request = (HttpServletRequest) resultMap.get("request");
    	String ip = WebUtils.retrieveClientIp(request);
    	
    	Date currentTime = new Date();
    	
    	List<Map<String, Object>> ipBlackMapList = this.findIPBlackList(ip, "", "", "", "");
    	
    	boolean isLock = true;
    	if (ipBlackMapList.size() > 0) {
    		
    		Map<String, Object> ipBlackMap = ipBlackMapList.get(0);
    		
    		Date invalidTime = (Date) ipBlackMap.get("INVALID_TIME");
    		String lockLevel = (String) ipBlackMap.get("LOCK_LEVEL");
    		if (isLock && "4".equals(lockLevel)) {
        		resultMap.put("error", true);
        		resultMap.put("errorMessage", "您的IP已被永久锁定，如需解锁请联系系统管理员。");
        		isLock = false;
    		} 
    		
    		if (isLock && currentTime.before(invalidTime)) {
        		resultMap.put("error", true);
        		resultMap.put("errorMessage", "您的IP将于" + DateUtils.toDateTime(invalidTime) + "后解锁，请稍后再试。");
        		isLock = false;
    		}
    	}	

		Date startTimeM15 = DateUtils.dayAddAndSub(Calendar.MINUTE , -15);
		int failCountM15 = this.oauthRepository.countLoginLogByIp(ip, DateUtils.toDateTime(startTimeM15), DateUtils.toDateTime(currentTime));
		Date startTimeM60 = DateUtils.dayAddAndSub(Calendar.HOUR , -1);
		int failCountM60 = this.oauthRepository.countLoginLogByIp(ip, DateUtils.toDateTime(startTimeM60), DateUtils.toDateTime(currentTime));
		Date startTimeH24 = DateUtils.dayAddAndSub(Calendar.DATE , -1);
		int failCountH24 = this.oauthRepository.countLoginLogByIp(ip, DateUtils.toDateTime(startTimeH24), DateUtils.toDateTime(currentTime));
		Date startTimeH72 = DateUtils.dayAddAndSub(Calendar.DATE , -3);
		int failCountH72 = this.oauthRepository.countLoginLogByIp(ip, DateUtils.toDateTime(startTimeH72), DateUtils.toDateTime(currentTime));
		
		if (isLock && failCountH72 >= 60) {
			IpBlackList ipBlackList = new IpBlackList();
			
			ipBlackList.setCreateTime(currentTime);
			ipBlackList.setUpdateTime(currentTime);
			ipBlackList.setInvalidTime(DateUtils.dayAddAndSub(Calendar.YEAR , 100));
			ipBlackList.setIP(ip);
			ipBlackList.setLockLevel("4");
			
			this.oauthRepository.saveIPBlackListInfo(ipBlackList);

    		resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的IP验证失败的次数过多，现已被永久锁定，如需解锁请联系系统管理员。");
    		isLock = false;
		} 
		
		if (isLock && failCountH24 >= 30) {
			IpBlackList ipBlackList = new IpBlackList();
			
			ipBlackList.setCreateTime(currentTime);
			ipBlackList.setUpdateTime(currentTime);
			ipBlackList.setInvalidTime(DateUtils.dayAddAndSub(Calendar.DATE , 1));
			ipBlackList.setIP(ip);
			ipBlackList.setLockLevel("3");
			
			this.oauthRepository.saveIPBlackListInfo(ipBlackList);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的IP验证失败的次数过多，现已被锁定，请在24小时之后再操作。");
    		isLock = false;
		}
		
		if (isLock && failCountM60 >= 25) {
			IpBlackList ipBlackList = new IpBlackList();
			
			ipBlackList.setCreateTime(currentTime);
			ipBlackList.setUpdateTime(currentTime);
			ipBlackList.setInvalidTime(DateUtils.dayAddAndSub(Calendar.MINUTE , 30));
			ipBlackList.setIP(ip);
			ipBlackList.setLockLevel("2");
			
			this.oauthRepository.saveIPBlackListInfo(ipBlackList);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的IP验证失败的次数过多，现已被锁定，请在30分钟之后再操作。");
    		isLock = false;
		}
		
		if (isLock && failCountM15 >= 15) {
			
			IpBlackList ipBlackList = new IpBlackList();
			
			ipBlackList.setCreateTime(currentTime);
			ipBlackList.setUpdateTime(currentTime);
			ipBlackList.setInvalidTime(DateUtils.dayAddAndSub(Calendar.MINUTE , 5));
			ipBlackList.setIP(ip);
			ipBlackList.setLockLevel("1");
			
			this.oauthRepository.saveIPBlackListInfo(ipBlackList);
			
			resultMap.put("error", true);
    		resultMap.put("errorMessage", "由于您的IP验证失败的次数过多，现已被锁定，请在5分钟之后再操作。");
    		isLock = false;
		}
	}

	@Override
	public Map<String, Object> findUserInfoByAppAccount(String appCode, String appAccount) {
		return this.oauthRepository.findUserInfoByAppAccount(appCode, appAccount);
	}

	@Override
	public Map<String, Object> findWedoStaffIdByAccount(String appCode, String userAccount) {
		
		String [] accountArr = userAccount.split(",");
		
		String accountStr = "";
		int count = 0;
		
		for (String account : accountArr) {
			if (count == 0) {
				accountStr += "'" + account + "'";
			} else {
				accountStr += ",'" + account + "'";
			}
			count++;
		}
		
		return this.oauthRepository.findWedoStaffIdByAccount(appCode, accountStr);
	}

	@Override
	public boolean bindAuthAccount(HttpServletRequest request, String appCode) throws NoSuchAlgorithmException {
		
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);
		
		try {
			password = DES3.decode(password, "ZGJMWQJSTMDZQQRDOONE" + String.valueOf(year));
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		
		String authAccount = request.getParameter("auth_account");
		
		Map<String, Object> userInfoMap = this.oauthRepository.findUserInfoByUserAccount(username);
		
		if (userInfoMap == null) {
			return false;
		}
		
		// mysql认证
		String tempStaffId = (String) userInfoMap.get("TEMP_STAFF_ID");
		String encryptionType = (String) userInfoMap.get("ENCRYPTION_TYPE");
		
		if (tempStaffId == null) {
			tempStaffId = "";
		}
		
		if (encryptionType.equals("1")) {
			password = PasswordUtils.md5Password(tempStaffId + password);
		} else if (encryptionType.equals("2")) {
			password = PasswordUtils.openLdapMD5(password);
		}
		
		boolean isCorrect = this.oauthRepository.isCorrectPassword(username, password);
		
		if (isCorrect) {
			userInfoMap.put("AUTH_ACCOUNT", authAccount);
			userInfoMap.put("APP_CODE", appCode);
			this.oauthRepository.saveAccountBinding(userInfoMap);
		}
		
		return isCorrect;
		
	}

	/**
	 * 根据微信公众号APPID获取绑定应用
	 */
	@Override
	public Map<String, Object> findAppInfoByWeChatId(String clientId, String appid) {
		return this.oauthRepository.findAppInfoByWeChatId(clientId, appid);
	}

	@Override
	public void changePasswordByUserInfoId(String userInfoId, String password, String p_code) {
		LOG.debug("change password userInfoId : {} and password : {}", userInfoId, password);
		this.oauthRepository.changePasswordByUserInfoId(userInfoId, password,p_code);
		
		if (propertiesUtils.isLdapEnable()) {
			// 修改ldap密码
			this.oauthLdapRepository.changePasswordByUserInfoId(userInfoId, password);
		}
	}

	@Override
	public boolean validCorrectPasswordByUserInfoId(String userInfoId, String password, HttpServletRequest request)
			throws Exception {
		LOG.debug("valid is password correct: ", password);
		
		Map<String, Object> userInfoMap = this.oauthRepository.findUserInfoByUserId(userInfoId);
		
		if (userInfoMap == null) {
			return false;
		}
		
		// mysql认证
		String tempStaffId = (String) userInfoMap.get("TEMP_STAFF_ID");
		String encryptionType = (String) userInfoMap.get("ENCRYPTION_TYPE");
		
		if (tempStaffId == null) {
			tempStaffId = "";
		}
		
		if (encryptionType.equals("1")) {
			password = PasswordUtils.md5Password(tempStaffId + password);
		} else if (encryptionType.equals("2")) {
			password = PasswordUtils.openLdapMD5(password);
		}
		
		
		boolean isCorrect = this.oauthRepository.isCorrectPasswordByUserInfoId(userInfoId, password);
		
		String userAccount = "";
		if (userInfoMap != null) {
			userAccount = userInfoMap.get("USER_ACCOUNT").toString();
		}
    	
		
		LoginLog loginLog = new LoginLog();
		String ipAdrress = WebUtils.retrieveClientIp(request);
		String macAddress = "";
		 
		loginLog.setUserInfoId(Integer.parseInt(userInfoId));
		loginLog.setUserAccount(userAccount);
		loginLog.setIsSuccess(isCorrect ? "1" : "0"); // 正确"1"，错误"0"
		loginLog.setIpAddress(ipAdrress);
		loginLog.setMacAddress(macAddress);
		
		this.oauthRepository.saveLoginLog(loginLog);
		return isCorrect;
	}
	
	public Map<String, Object> findUserInfoByUserId(String userInfoId) {
		return this.oauthRepository.findUserInfoByUserId(userInfoId);
	}

	@Override
	public Map<String, Object> queryInfoByToken(String token) {
		return this.oauthRepository.queryInfoByToken(token);
	}

	
}
